from datetime import datetime, timedelta
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import CreateModelMixin
from rest_framework import status
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated

import utils
from . import models
from . import serializer


class PayAPIView(CreateModelMixin, GenericViewSet):
    # 对PayView类进行限制. 使用内置限制(认证 + 权限)
    authentication_classes = [JSONWebTokenAuthentication]
    permission_classes = [IsAuthenticated]

    queryset = models.Order.objects.all()
    serializer_class = serializer.OrderModelSeriailzer

    def create(self, request, *args, **kwargs):
        # 视图中重写create方法借助self.context传将request对象传给序列化类
        ser = self.get_serializer(data=request.data, context={'request': request})
        ser.is_valid(raise_exception=True)
        self.perform_create(ser)
        headers = self.get_success_headers(ser.data)
        # 视图中: Response返回给前端的, 前端只需要一个连接, 那么序列化校验的第五步, 在self.context中将它存入, 将它返回给前端
        return utils.APIResponse(result=ser.context['pay_link'], status=status.HTTP_201_CREATED, headers=headers)


from rest_framework.views import APIView
from django.db.models.query import QuerySet
from libs.alipay_sdk import alipay


class SuccessView(APIView):
    def get(self, request, *args, **kwargs):
        """
        获取前端传递过来的 out_trade_no, 去数据库中查取, 判断订单 order_status 的订单状态是否成功.
        最后返回响应中通过code=0或者code=1返回给前端即可
        """
        out_trade_no = request.query_params.get('out_trade_no')
        order = models.Order.objects.filter(out_trade_no=out_trade_no).first()
        order_detail_list = order.order_detail_list
        member_dict = order.order_details.all()[0].member_dict
        # order.order_status值为1表示订单成功
        if order.order_status == 1:
            return utils.APIResponse()
        return utils.APIResponse(code=0, msg='失败', result=order_detail_list, member_dict=member_dict)

    def post(self, request, *args, **kwargs):
        """
        回调地址: https://github.com/fzlee/alipay/blob/master/README.zh-hans.md#alipay.fund.trans.toaccount.transfer
        回调参数: https://opendocs.alipay.com/open/270/105902/
        注意: 必须data内容返回 success
            request.data可能有2种情况. 如果是json格式是字典, 如果是QuseryDict需要注意
        失败了之后需要记录日志
        成功了之后需要记录日志, 并且修改订单状态, 使用 out_trade_no 作为过来标志, order_status修改为1, 交易支付时间pay_time=gmt_payment
        """
        # request.data类型判断
        data = request.data
        utils.log(f'request.data: {request.data}')
        if isinstance(data, QuerySet):
            data = dict(data).pop('sign')

        signature = data.pop("sign")
        out_trade_no = data.get('out_trade_no')
        gmt_payment = data.get('gmt_payment')

        # 校验
        success = alipay.verify(data, signature)
        if success and data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
            # 修改订单状态
            order = models.Order.objects.filter(out_trade_no=out_trade_no).first()
            order.update(order_status=1, pay_time=gmt_payment)
            order.save()

            # 为用户充值会员时间
            member = order.order_details.all()[0].member
            recharge_time = timedelta(days=member.buy_month * 30 + member.give_day)
            user = models.User.objects.filter(pk=order.user.id)
            # 用户第一次
            if user.is_first:
                user.is_first = False
            if not user.is_expire:
                # 用户没到期
                user.expire_time = user.expire_time + recharge_time
            else:
                # 用户到期
                user.expire_time = datetime.now() + recharge_time
            user.is_expire = False
            user.user_type = 1
            user.save()

            utils.log.info(f'{out_trade_no}订单支付成功!')
            # !!!注意!!!: 服务器异步通知页面特性
            '''
            当商户收到服务器异步通知并打印出 success 时，服务器异步通知参数 notify_id 才会失效。
            也就是说在支付宝发送同一条异步通知时（包含商户并未成功打印出 success 导致支付宝重发数次通知），服务器异步通知参数 notify_id 是不变的。
            '''
            return utils.APIResponse(data='success')
